package preferscala;
import sbinary._;
import sbinary.Operations._;
import java.io.File;
import java.util.prefs.Preferences;

sealed abstract class PreferenceType{
  private[preferscala] def nodeForPackage(clazz : Class[_]) : Preferences;
  private[preferscala] def root : Preferences;
}

object PreferenceType{
  case object User extends PreferenceType{
    private[preferscala] def nodeForPackage(clazz : Class[_]) = Preferences.userNodeForPackage(clazz);
    private[preferscala] def root = Preferences.userRoot;
  }

  case object System extends PreferenceType{
    private[preferscala] def nodeForPackage(clazz : Class[_]) = Preferences.systemNodeForPackage(clazz);
    private[preferscala] def root = Preferences.systemRoot;
  }
}

abstract class PreferenceGroup{
  def underlying : Preferences; 
  class Preference[T](name : String, default : => T)(implicit bin : Binary[T]){
    private var localCache : T = null.asInstanceOf[T];

    private val preference = underlying.node(name);

    def apply() : T = {
      if (localCache == null){
        var bytes = preference.getByteArray("", null);
        if (bytes == null){
          localCache = default;
        } else {
          localCache = fromByteArray[T](bytes)
        } 
      }
      localCache
    }

    def update(t : T){
      localCache = t;
      preference.putByteArray("", toByteArray[T](t));
    }

    def reset(){
      localCache = null.asInstanceOf[T];
      preference.remove("");
      preference.flush();
    }

    def exportToFile(file : File){
      toFile(apply())(file);
    }

    def loadFromFile(file : File){
      update(fromFile[T](file));
    }
  }
}

class NamedGroup(groupName : String, pt : PreferenceType) extends PreferenceGroup{
  val underlying = pt.root.node(groupName);
}

abstract class PackageGroup(pt : PreferenceType) extends PreferenceGroup{
  val underlying = pt.nodeForPackage(getClass);
} 
